#include "showinfo.h"
#include "ui_showinfo.h"
#include <QVector>
#include <QString>
#include <QDebug>
#include <ifaddrs.h> // 定义struct ifaddrs
#include <net/if.h>  // 定义nametoindex
#include <arpa/inet.h> // 定义inet_ntop
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <netinet/in.h>
#include <QComboBox>
#include <QFile>
#include <QDir>

// 以太网族 AF_PACKET 17
// IPv4族 AF_INET 2
// IPv6族 AF_INET6 10


void ShowInfo::initMac()
{
    QString systemFolderPath = "/sys/class/net/";
    QDir systemFolder(systemFolderPath);
    if (!systemFolder.exists()) {
        qDebug() << "System folder does not exist.";
        return;
    }
    if (!systemFolder.isReadable()) {
        qDebug() << "No read permission for system folder.";
        return;
    }

    // 读取并打印目录中的文件列表
    QStringList dirs = systemFolder.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
    for (const QString& dir : dirs) {
//        qDebug() << dir;
        QString filename = systemFolderPath + dir + "/address";
//        qDebug() << filename;
        QFile file(filename);
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QByteArray array = file.readAll();  //读取文本中全部文件
            auto it = this->infoList.begin();
            for (; it != this->infoList.end(); ++it)
            {
                if ((*it)->name == dir)
                {
                    (*it)->mac = QString(array);
                    (*it)->mac.chop(1); // 去除换行符
                    break;
                }
            }
            if (it == this->infoList.end())
            {
                Info* tmp = new Info(dir, "未启用", "未启用");
                this->infoList.push_back(tmp);
                tmp->mac = QString(array);
                tmp->mac.chop(1);
            }
//            qDebug() << QString(array);
            file.close();
        } else {
            qDebug() << "Failed to open the mac file.";
        }
    }
}

void ShowInfo::initIpInfo()
{
    struct ifaddrs *ifaddr;
    if (getifaddrs(&ifaddr) == -1)
    {
//        qDebug() << "get info failed";
    }
    else
    {
//        qDebug() << "get info successed";
    }

    // 可以理解ifaddr为一个链表，遍历这个链表，筛选出以太网族
    for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
    {
        // ipv4族
        if (ifa->ifa_addr->sa_family == AF_INET)
        {
//            qDebug() << "Interface Name: " << ifa->ifa_name;
            if (ifa->ifa_addr != nullptr && ifa->ifa_netmask != nullptr)
            {
                char ip[64] = {0};
                inet_ntop(AF_INET, &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), ip, 64);
//                qDebug() << ip;
                char mask[64] = {0};
                inet_ntop(AF_INET, &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr), mask, 64);
//                qDebug() << mask;
                Info* tmp = new Info(ifa->ifa_name, ip, mask);
                this->infoList.push_back(tmp);
            }
        }
    }
    freeifaddrs(ifaddr);
}


ShowInfo::ShowInfo(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ShowInfo)
{
    ui->setupUi(this);
}

ShowInfo::~ShowInfo()
{
    destroyInfo();
    delete ui;
}

void ShowInfo::on_choose_currentTextChanged(const QString &arg1)
{
    for (auto it = this->infoList.begin(); it != this->infoList.end(); ++it)
    {
        if ((*it)->name == arg1)
        {
            ui->ip->setText((*it)->ip);
            ui->mask->setText((*it)->mask);
            ui->mac->setText((*it)->mac);
            break;
        }
    }
}

void ShowInfo::on_init_clicked()
{
    ui->choose->clear();
    // 销毁infoList
    destroyInfo();
    // 初始化ip、mac
    initIpInfo();
    initMac();
    // 添加combobox
    for (auto it = this->infoList.begin(); it != this->infoList.end(); ++it)
    {
        ui->choose->addItem((*it)->name);
    }

    ui->textBrowser->clear();
    initTcpStatus();
//    system("netstat -t");
}

void ShowInfo::destroyInfo()
{
    for (auto it = this->infoList.begin(); it != this->infoList.end(); ++it)
    {
//        qDebug() << (*it)->name;
        delete (*it);
    }
    this->infoList.clear();
}

void ShowInfo::initTcpStatus()
{
    QString filename = "/proc/net/tcp";
    QFile file(filename);
    if (file.exists())
    {
        // qDebug() << "tcp file exist";

    }
    else
    {
        qDebug() << "tcp file not exist";
    }
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "open tcp file failed";
    }

//    qDebug() << file.atEnd();
    QByteArray line;
    line = file.readLine();
    qDebug() << line;
    QString title = "  序号        本地地址和端口            远程地址和端口         连接状态";
//    ui->showTcpPort->setText(title);
    ui->textBrowser->insertPlainText(title);
    qDebug() << title;
    QString eachLine = "";
    // !!!file.atEnd()在读取文件后才正确返回
    while (!file.atEnd())
    {
        line = file.readLine();
//        qDebug() << line;
        // 作用等同于split
        QVector<QString> infoStrs;  // 初始分割
        QString curStr = "";
        for (int i = 0; i < line.size(); ++i)
        {
            if (line[i] == ' ')
            {
                if (curStr != "")
                {
                    infoStrs.push_back(curStr);
                    curStr.clear();
                }
                continue;
            }
            curStr += line[i];
        }
//        for (int i = 0; i < infoStrs.size(); ++i)
//        {
//            qDebug() << infoStrs[i];
//        }
        // 处理序号
        curStr = convertSeq(infoStrs[0]);
        eachLine += curStr;
        eachLine += QString(2, ' ');
        // 处理本地地址和端口号
        curStr = convertIp(infoStrs[1]);
        eachLine += curStr;
        eachLine += QString(4, ' ');
        // 处理远程地址和端口号
        curStr = convertIp(infoStrs[2]);
        eachLine += curStr;
        eachLine += QString(3, ' ');
        // 处理连接状态
        curStr = convertLink(infoStrs[3]);
        eachLine += curStr;
//        eachLine += '\n';
        ui->textBrowser->append(eachLine);
        qDebug() << eachLine;
        eachLine.clear();
//
//        ui->showTcpPort->insertPlainText(eachLine);
    }
    file.close();

}
QString ShowInfo::convertSeq(QString &seq)
{
    QString show = "";
    for (int i = 0; i < seq.size() - 1; ++i)
    {
        show += seq[i];
    }
    int pre = 4 - show.size();
    show = QString(pre, ' ') + show;
    return show;
}
QString ShowInfo::convertIp(QString &ip)
{
    QString show = "";
    int n1 = charWeight(ip[6]) * 16 + charWeight(ip[7]);
    show += QString::number(n1);
    show += '.';
    n1 = charWeight(ip[4]) * 16 + charWeight(ip[5]);
    show += QString::number(n1);
    show += '.';
    n1 = charWeight(ip[2]) * 16 + charWeight(ip[3]);
    show += QString::number(n1);
    show += '.';
    n1 = charWeight(ip[0]) * 16 + charWeight(ip[1]);
    show += QString::number(n1);
    int pre = 15 - show.size();
    show = QString(pre, ' ') + show;
    show += ':';
    n1 = (charWeight(ip[9]) * 16 * 16 * 16 + charWeight(ip[10]) * 16 * 16 + charWeight(ip[11]) * 16 + charWeight(ip[12]));
    int portPre = 5 - QString::number(n1).size();
    show += QString::number(n1);
    show += QString(portPre, ' ');
    return show;
}

int ShowInfo::charWeight(QChar ch)
{
    char c = ch.toLatin1();
    switch (c) {
    case '0':
        return 0;
    case '1':
        return 1;
    case '2':
        return 2;
    case '3':
        return 3;
    case '4':
        return 4;
    case '5':
        return 5;
    case '6':
        return 6;
    case '7':
        return 7;
    case '8':
        return 8;
    case '9':
        return 9;
    case 'A':
        return 10;
    case 'B':
        return 11;
    case 'C':
        return 12;
    case 'D':
        return 13;
    case 'E':
        return 14;
    case 'F':
        return 15;
    default:
        return -1;
    }
}

QString ShowInfo::convertLink(QString &link)
{

    if (link == "01")
    {
        return "ESTABLISHED";
    }
    if (link == "02")
    {
        return "  SYN_SENT ";
    }
    if (link == "03")
    {
        return "  SYN_RECV ";
    }
    if (link == "04")
    {
        return " FIN_WAIT1 ";
    }
    if (link == "05")
    {
        return " FIN_WAIT2 ";
    }
    if (link == "06")
    {
        return " TIME_WAIT ";
    }
    if (link == "07")
    {
        return "   CLOSE   ";
    }
    if (link == "08")
    {
        return " CLOSE_WAIT";
    }
    if (link == "09")
    {
        return "  LAST_ACK ";
    }
    if (link == "0A")
    {
        return "   LISTEN  ";
    }
    return "other";
}
